package cn.flying.cloud.system.user.service.impl;

import javax.annotation.Resource;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.flying.cloud.base.common.bo.UserInfo;
import cn.flying.cloud.base.common.constants.Constants;
import cn.flying.cloud.base.common.exception.BizException;
import cn.flying.cloud.base.common.utils.Ft;
import cn.flying.cloud.base.common.vo.PageRequest;
import cn.flying.cloud.base.common.vo.PageResponse;
import cn.flying.cloud.base.redis.service.RedisService;
import cn.flying.cloud.common.enums.SeqTypeEnum;
import cn.flying.cloud.common.enums.StatusEnum;
import cn.flying.cloud.system.log.service.SysSeqInfoService;
import cn.flying.cloud.system.org.entity.SysOrgInfo;
import cn.flying.cloud.system.org.service.SysOrgInfoService;
import cn.flying.cloud.system.position.entity.SysPostUser;
import cn.flying.cloud.system.position.service.SysPostUserService;
import cn.flying.cloud.system.resource.entity.SysResInfo;
import cn.flying.cloud.system.resource.service.SysResInfoService;
import cn.flying.cloud.system.user.entity.SysUserInfo;
import cn.flying.cloud.system.user.entity.SysUserRole;
import cn.flying.cloud.system.user.mapper.SysUserInfoMapper;
import cn.flying.cloud.system.user.service.SysUserInfoService;
import cn.flying.cloud.system.user.service.SysUserRoleService;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2024-04-02 13:08:33
 */
@Service
public class SysUserInfoServiceImpl extends ServiceImpl<SysUserInfoMapper, SysUserInfo> implements SysUserInfoService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final String key = "878a3540cfc344d48353ab799d154623";

    @Resource
    private SysOrgInfoService sysOrgInfoService;
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private SysPostUserService sysPostUserService;
    @Resource
    private SysResInfoService sysResInfoService;
    @Resource
    private SysSeqInfoService sysSeqInfoService;
    @Resource
    private RedisService redisService;

    /**
     * 分页查询用户信息表数据
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<SysUserInfo> getPageList(PageRequest<SysUserInfo> request) {
        SysUserInfo param = request.getParam();
        LambdaQueryWrapper<SysUserInfo> wrapper = getLambdaQueryWrapper(param);
        Page<SysUserInfo> page = this.page(new Page<>(request.getPageNum(), request.getPageSize()), wrapper);
        return new PageResponse<>(page.getTotal(), (int) page.getCurrent(), page.getRecords());
    }

    /**
     * 构建查询对象
     *
     * @param param
     * @return
     */
    private LambdaQueryWrapper<SysUserInfo> getLambdaQueryWrapper(SysUserInfo param) {
        LambdaQueryWrapper<SysUserInfo> wrapper = new LambdaQueryWrapper<>();
        if (param != null) {
            if (Ft.String.isNotBlank(param.getOrgId())) {
                wrapper.eq(SysUserInfo::getOrgId, param.getOrgId());
            }
            if (Ft.String.isNotBlank(param.getUsername())) {
                wrapper.eq(SysUserInfo::getUsername, param.getUsername());
            }
            if (Ft.String.isNotBlank(param.getUserId())) {
                wrapper.eq(SysUserInfo::getUserId, param.getUserId());
            }
            if (Ft.String.isNotBlank(param.getMobile())) {
                wrapper.eq(SysUserInfo::getMobile, param.getMobile());
            }
            if (Ft.String.isNotBlank(param.getLocked())) {
                wrapper.eq(SysUserInfo::getLocked, param.getLocked());
            }
            if (Ft.String.isNotBlank(param.getStatus())) {
                wrapper.eq(SysUserInfo::getStatus, param.getStatus());
            }
        }
        return wrapper;
    }

    /**
     * 列表查询用户信息表数据
     *
     * @param sysUserInfo
     * @return
     */
    @Override
    public List<SysUserInfo> getList(SysUserInfo sysUserInfo) {
        LambdaQueryWrapper<SysUserInfo> wrapper = getLambdaQueryWrapper(sysUserInfo);
        return this.list(wrapper);
    }

    /**
     * 获取所有的用户信息表数据
     *
     * @return
     */
    @Override
    public List<SysUserInfo> getAllUserList() {
        LambdaQueryWrapper<SysUserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserInfo::getStatus, StatusEnum.STATUS_Y.getCode());
        return this.list(wrapper);
    }

    /**
     * 查询用户信息表详情数据
     *
     * @param sysUserInfo
     * @return
     */
    @Override
    public SysUserInfo getOneObj(SysUserInfo sysUserInfo) {
        LambdaQueryWrapper<SysUserInfo> wrapper = getLambdaQueryWrapper(sysUserInfo);
        return this.getOne(wrapper);
    }


    /**
     * 新增用户信息表数据
     *
     * @param sysUserInfo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean createObj(SysUserInfo sysUserInfo) {
        // 检查用户名是否已存在
        LambdaQueryWrapper<SysUserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserInfo::getUsername, sysUserInfo.getUsername());
        SysUserInfo existingUser = this.getOne(queryWrapper);
        if (existingUser != null) {
            throw new BizException("用户名已存在");
        }
        SysOrgInfo sysOrgInfo = new SysOrgInfo();
        sysOrgInfo.setOrgId(sysUserInfo.getOrgId());
        sysOrgInfo = sysOrgInfoService.getOneObj(sysOrgInfo);
        //保存组织机构信息
        sysUserInfo.setOrgName(sysOrgInfo.getOrgName());
        sysUserInfo.setOrgPath(sysOrgInfo.getOrgPath());
        // 获取用户Id
        String userId = sysSeqInfoService.getNextSeq(SeqTypeEnum.USER.name());
        sysUserInfo.setUserId(userId);

        sysUserInfo.setPassword(Ft.SM3.encrypt("Rot1qaz2wsx,.", key));

        // 保存新的用户角色信息
        if (Ft.String.isNotBlank(sysUserInfo.getRoleId())) {
            String[] roleIds = sysUserInfo.getRoleId().split(",");
            SysUserRole userRole;
            List<SysUserRole> roles = new ArrayList<>();
            for (String roleId : roleIds) {
                userRole = new SysUserRole();
                userRole.setUserId(userId);
                userRole.setRoleId(roleId);
                userRole.setTenantId(Ft.Local.TenantId());
                roles.add(userRole);
            }
            sysUserRoleService.saveBatch(roles);
        }

        // 保存新的用户岗位信息
        if (Ft.String.isNotBlank(sysUserInfo.getPostId())) {
            String[] postIds = sysUserInfo.getPostId().split(",");
            SysPostUser postUser;
            List<SysPostUser> postUsers = new ArrayList<>();
            for (String postId : postIds) {
                postUser = new SysPostUser();
                postUser.setUserId(userId);
                postUser.setPostId(postId);
                postUser.setTenantId(Ft.Local.TenantId());
                postUsers.add(postUser);
            }
            sysPostUserService.saveBatch(postUsers);
        }
        sysUserInfo.setTenantId(Ft.Local.TenantId());
        return this.save(sysUserInfo);
    }

    /**
     * 更新用户信息表数据
     *
     * @param sysUserInfo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateObj(SysUserInfo sysUserInfo) {
        SysOrgInfo sysOrgInfo = new SysOrgInfo();
        sysOrgInfo.setOrgId(sysUserInfo.getOrgId());
        sysOrgInfo = sysOrgInfoService.getOneObj(sysOrgInfo);
        //保存组织机构信息
        sysUserInfo.setOrgName(sysOrgInfo.getOrgName());
        sysUserInfo.setOrgPath(sysOrgInfo.getOrgPath());
        // 删除原来的用户角色信息
        LambdaQueryWrapper<SysUserRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(SysUserRole::getUserId, sysUserInfo.getUserId());
        sysUserRoleService.remove(roleWrapper);

        // 保存新的用户角色信息
        if (Ft.String.isNotBlank(sysUserInfo.getRoleId())) {
            String[] roleIds = sysUserInfo.getRoleId().split(",");
            SysUserRole userRole;
            List<SysUserRole> roles = new ArrayList<>();
            for (String roleId : roleIds) {
                userRole = new SysUserRole();
                userRole.setUserId(sysUserInfo.getUserId());
                userRole.setRoleId(roleId);
                userRole.setTenantId(Ft.Local.TenantId());
                roles.add(userRole);
            }
            sysUserRoleService.saveBatch(roles);
        }

        // 删除原来的用户岗位信息
        LambdaQueryWrapper<SysPostUser> postUserWrapper = new LambdaQueryWrapper<>();
        postUserWrapper.eq(SysPostUser::getUserId, sysUserInfo.getUserId());
        sysPostUserService.remove(postUserWrapper);

        // 保存新的用户岗位信息
        if (Ft.String.isNotBlank(sysUserInfo.getPostId())) {
            String[] postIds = sysUserInfo.getPostId().split(",");
            SysPostUser postUser;
            List<SysPostUser> postUsers = new ArrayList<>();
            for (String postId : postIds) {
                postUser = new SysPostUser();
                postUser.setUserId(sysUserInfo.getUserId());
                postUser.setPostId(postId);
                postUser.setTenantId(Ft.Local.TenantId());
                postUsers.add(postUser);
            }
            sysPostUserService.saveBatch(postUsers);
        }
        return this.saveOrUpdate(sysUserInfo);
    }

    /**
     * 删除用户信息表数据
     *
     * @param sysUserInfo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteObj(SysUserInfo sysUserInfo) {
        LambdaQueryWrapper<SysUserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserInfo::getUserId, sysUserInfo.getUserId());
        boolean removed = this.remove(wrapper);

        // 同时删除用户角色信息
        LambdaQueryWrapper<SysUserRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(SysUserRole::getUserId, sysUserInfo.getUserId());
        sysUserRoleService.remove(roleWrapper);

        // 同时删除用户岗位信息
        LambdaQueryWrapper<SysPostUser> postWrapper = new LambdaQueryWrapper<>();
        postWrapper.eq(SysPostUser::getUserId, sysUserInfo.getUserId());
        sysPostUserService.remove(postWrapper);

        return removed;
    }

    /**
     * 根据Id删除
     *
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteById(Serializable id) {
        return this.removeById(id);
    }

    /**
     * 重置用户密码
     *
     * @param sysUserInfo
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean reset(SysUserInfo sysUserInfo) {
        LambdaQueryWrapper<SysUserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserInfo::getUserId, sysUserInfo.getUserId());
        SysUserInfo info = this.getOne(wrapper);
        if (info == null) {
            throw new BizException("用户不存在");
        }
        info.setPassword(Ft.SM3.encrypt(sysUserInfo.getPassword(), key));
        return this.updateById(info);
    }

    /**
     * 查询用户认证信息
     *
     * @param username
     * @param type
     * @return
     */
    @Override
    public UserInfo getUserAuthInfo(String username, String type) {
        UserInfo authInfo = new UserInfo();

        LambdaQueryWrapper<SysUserInfo> wrapper = new LambdaQueryWrapper<>();
        if ("mobile".equals(type)) {
            wrapper.eq(SysUserInfo::getMobile, username);
        } else if ("email".equals(type)) {
            wrapper.eq(SysUserInfo::getEmail, username);
        } else {
            // 默认按照用户名查询
            wrapper.eq(SysUserInfo::getUsername, username);
        }
        SysUserInfo sysUserInfo = this.getOne(wrapper);

        Ft.BeanCopier.copy(sysUserInfo, authInfo);

        //用户权限集合（角色、资源权限）
        Set<String> perms = new HashSet<>();
        authInfo.setPerms(perms);

        if (Ft.String.isNotBlank(sysUserInfo.getRoleId())) {
            authInfo.setRoles(Arrays.stream(sysUserInfo.getRoleId().split(",")).collect(Collectors.toSet()));
            //处理角色，增加前缀“ROLE_”
            List<String> roles = Arrays.stream(sysUserInfo.getRoleId().split(",")).map(roleId -> "ROLE_" + roleId).distinct().collect(Collectors.toList());
            perms.addAll(roles);
        }

        //查询用户资源权限
        List<SysResInfo> sysResInfos = sysResInfoService.getResInfosByUserId(sysUserInfo.getUserId(), sysUserInfo.getTenantId());
        if (CollectionUtils.isNotEmpty(sysResInfos)) {
            Set<String> set = sysResInfos.stream().map(SysResInfo::getMid).filter(Ft.String::isNotBlank).collect(Collectors.toSet());
            perms.addAll(set);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("查询返回用户相关信息：【{}】", Ft.JSON.serializer(authInfo));
        }

        //将用户的角色、资源、权限保存到Redis缓存中
        redisService.set(Constants.AUTH_PRINCIPAL + ":" + authInfo.getTenantId() + ":" + authInfo.getUserId(), Ft.JSON.serializer(authInfo));

        // TODO 控制访问url级别
//        Map<String, Object> map = sysResInfos.stream().collect(Collectors.toMap(SysResInfo::getPath, SysResInfo::getMid));
        // 缓存用户的权限标识与资源的映射
//        redisService.hmset(Constants.AUTH_PERMS + ":" + authInfo.getTenantId() + ":" + authInfo.getUserId(), map);

        return authInfo;
    }

    /**
     * 同步注册用户信息
     *
     * @param authInfo
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String register(UserInfo authInfo) {
        SysUserInfo sysUserInfo = new SysUserInfo();

        Ft.BeanCopier.copy(authInfo, sysUserInfo);
        // 获取用户Id
        String userId = sysSeqInfoService.getNextSeq(SeqTypeEnum.USER.name());
        sysUserInfo.setUserId(userId);
        this.save(sysUserInfo);

        return userId;
    }

    @Override
    public void updateUserPwd(String oldPassword, String newPassword) {
        String userId = (String) Ft.ThreadLocal.get(Constants.USER_ID);
        SysUserInfo sysUserInfo = new SysUserInfo();
        sysUserInfo.setUserId(userId);
        SysUserInfo userInfo = this.getOneObj(sysUserInfo);
        String oldPasswordEncrypt = Ft.SM3.encrypt(oldPassword, key);
        String newPasswordEncrypt = Ft.SM3.encrypt(newPassword, key);

        if (!StringUtils.equals(userInfo.getPassword(), oldPasswordEncrypt)) {
            throw new BizException("旧密码不正确");
        } else if (StringUtils.equals(userInfo.getPassword(), newPasswordEncrypt)) {
            throw new BizException("新密码不能与旧密码相同");
        }

        userInfo.setPassword(newPasswordEncrypt);
        this.updateById(userInfo);
    }
}
